#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
图片混淆器
修改图片文件的MD5值，但不影响显示效果
"""

import os
import random
import shutil
from pathlib import Path
from typing import List, Optional

from core.builtin_config_module.builtin_config import BuiltInConfig
from core.utils_module.logger import ObfuscationLogger


class ImageObfuscator:
    """图片混淆器 - 修改图片MD5但保持显示效果"""

    # 支持的图片格式
    SUPPORTED_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.webp'}

    def __init__(self, config: BuiltInConfig, logger: ObfuscationLogger):
        """
        初始化图片混淆器

        Args:
            config: 统一配置对象
            logger: 日志记录器
        """
        self.config = config
        self.logger = logger
        self.backup_dir = None
        self.modified_count = 0

    def modify_project_images(self, project_path: str,
                              create_backup: bool = True) -> bool:
        """
        修改项目中所有图片的MD5值

        Args:
            project_path: 项目路径
            create_backup: 是否创建备份

        Returns:
            是否成功
        """
        try:
            self.logger.log_operation("图片混淆", f"开始处理项目: {project_path}")

            if not os.path.exists(project_path):
                self.logger.log_error(f"图片混淆失败: 项目路径不存在 {project_path}")
                return False

            # 创建备份目录
            if create_backup:
                self.backup_dir = os.path.join(project_path, '.image_backup')
                os.makedirs(self.backup_dir, exist_ok=True)
                self.logger.log_operation("备份创建", f"备份目录: {self.backup_dir}")

            # 查找所有图片文件
            image_files = self._find_images(project_path)

            if not image_files:
                self.logger.log_warning("未找到图片文件")
                return True

            self.logger.log_operation("图片发现", f"找到 {len(image_files)} 个图片文件")

            # 处理每个图片
            self.modified_count = 0
            for image_path in image_files:
                if self._modify_single_image(image_path, create_backup):
                    self.modified_count += 1

            self.logger.log_operation(
                "图片混淆完成",
                f"成功修改 {self.modified_count}/{len(image_files)} 个图片"
            )

            return True

        except Exception as e:
            self.logger.log_error(f"图片混淆失败: {e}")
            return False

    def restore_images(self, project_path: str) -> bool:
        """
        从备份还原图片文件

        Args:
            project_path: 项目路径

        Returns:
            是否成功
        """
        try:
            backup_dir = os.path.join(project_path, '.image_backup')

            if not os.path.exists(backup_dir):
                self.logger.log_warning("没有找到图片备份")
                return False

            self.logger.log_operation("图片还原", "开始还原图片文件")

            restored_count = 0
            for backup_file in os.listdir(backup_dir):
                backup_path = os.path.join(backup_dir, backup_file)

                # 查找原文件位置
                for root, _, files in os.walk(project_path):
                    if '.image_backup' in root:
                        continue

                    if backup_file in files:
                        original_path = os.path.join(root, backup_file)
                        shutil.copy2(backup_path, original_path)
                        restored_count += 1
                        self.logger.log_file_processing(original_path, "已还原")
                        break
                else:
                    original_path = os.path.join(project_path, backup_file)
                    if not os.path.exists(os.path.dirname(original_path)):
                        os.makedirs(os.path.dirname(original_path), exist_ok=True)
                    shutil.copy2(backup_path, original_path)
                    restored_count += 1
                    self.logger.log_file_processing(original_path, "已还原（原始位置缺失，已还原到项目根目录）")

            self.logger.log_operation(
                "图片还原完成",
                f"成功还原 {restored_count} 个图片文件"
            )

            return True

        except Exception as e:
            self.logger.log_error(f"还原图片失败: {e}")
            return False

    def clean_backups(self, project_path: str) -> bool:
        """
        清理图片备份

        Args:
            project_path: 项目路径

        Returns:
            是否成功
        """
        try:
            backup_dir = os.path.join(project_path, '.image_backup')

            if os.path.exists(backup_dir):
                shutil.rmtree(backup_dir)
                self.logger.log_operation("备份清理", "图片备份已清理")

            return True

        except Exception as e:
            self.logger.log_error(f"清理图片备份失败: {e}")
            return False

    def _find_images(self, project_path: str) -> List[str]:
        """
        查找项目中的所有图片文件

        Args:
            project_path: 项目路径

        Returns:
            图片文件路径列表
        """
        image_files = []

        for root, dirs, files in os.walk(project_path):
            # 跳过备份目录和其他隐藏目录
            dirs[:] = [d for d in dirs if not d.startswith('.')
                      and d not in ['build', 'dist', '__pycache__', 'node_modules']]

            for file in files:
                ext = Path(file).suffix.lower()
                if ext in self.SUPPORTED_EXTENSIONS:
                    image_files.append(os.path.join(root, file))

        return image_files

    def _modify_single_image(self, image_path: str, create_backup: bool = True) -> bool:
        """
        修改单个图片文件的MD5

        原理：在图片文件末尾添加随机字节，不影响图片显示，但改变MD5

        Args:
            image_path: 图片文件路径
            create_backup: 是否创建备份

        Returns:
            是否成功
        """
        try:
            # 创建备份
            if create_backup and self.backup_dir:
                backup_path = os.path.join(
                    self.backup_dir,
                    os.path.basename(image_path)
                )
                shutil.copy2(image_path, backup_path)

            # 读取原始文件内容
            with open(image_path, 'rb') as f:
                content = f.read()

            # 在文件末尾添加随机字节
            # 大多数图片格式会忽略文件末尾的额外数据
            random_bytes = os.urandom(random.randint(1, 10))
            modified_content = content + random_bytes

            # 写回文件
            with open(image_path, 'wb') as f:
                f.write(modified_content)

            self.logger.log_file_processing(image_path, "MD5已修改")
            return True

        except Exception as e:
            self.logger.log_warning(f"修改图片失败 {image_path}: {e}")
            return False

    def get_statistics(self) -> dict:
        """
        获取处理统计信息

        Returns:
            统计信息字典
        """
        return {
            'modified_count': self.modified_count,
            'backup_dir': self.backup_dir
        }
